/****************************************************************
* @file   : calc_hash.cpp
* @author : NingJian (freegodly@gmail.com)
* @date   : 05/27/21 15:25:25
* @brief  :  通过输入的 head seed boundary nonce 计算结果
****************************************************************/

#include <iostream>
#include "eth_types.h"
#include "eth_func.hpp"
#include <memory>
#include "pcie_tools.hpp"
#include <chrono>
#include <fstream>


using namespace std;
using namespace eth;
using namespace eth::mcore;
using namespace std::chrono;
using timer = std::chrono::steady_clock;


int main(int argc, char *argv[])
{
    cout << "---------------说明-----------------" << endl;
    cout << "输入head seed boundary nonce 字符串值，计算下一个hash" << endl;
    cout << "例如 ./calc_hash  0x3d36e0e4bf38e352bdde11dabd8beed9da63647b69fc6dcfbac3a8d53653da8f  0x3646e1f9abad7750d559c03326ae5841c98e2fff3ee4ef7e1bc354b4499c946d  0x000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffff  15124831206855771273" << endl;


    std::string sHeaderHash = "0x3d36e0e4bf38e352bdde11dabd8beed9da63647b69fc6dcfbac3a8d53653da8f";
    std::string sSeedHash   ="0x3646e1f9abad7750d559c03326ae5841c98e2fff3ee4ef7e1bc354b4499c946d";
    std::string sShareTarget="0x000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffff";

    size_t sNonce = 15124831206855771273UL;

    if (argc == 5)
    {
        sHeaderHash = std::string(argv[1]);
        sSeedHash = std::string(argv[2]);
        sShareTarget = std::string(argv[3]);
        sNonce = std::stoul(std::string(argv[4]));
    }

   hash256 seed = hash256_from_string(sSeedHash);
   hash256 header = hash256_from_string(sHeaderHash);
   hash256 boundary = hash256_from_string(sShareTarget);

   cout << "seed : " << hash256_to_string(seed) << endl;
   cout << "header : " << hash256_to_string(header) << endl;
   cout << "boundary : " << hash256_to_string(boundary) << endl;


    int epoch = find_epoch_number(seed);
    std::cout << "epoch : " << epoch << endl;

    std::string file_name = std::string("dag_epoch_") + std::to_string(epoch) + ".dat";
    std::cout << "try load dag file: " <<  file_name << endl;

    const size_t full_dataset_num_items = eth_calculate_dataset_num_items(epoch); 
    void * dag = malloc(full_dataset_num_items * 128);
   
    ifstream inFile(file_name,ios::in|ios::binary);
    if(!inFile) {
        cout << "open dag file error!" <<endl;
        return 0;
    }
    inFile.read((char *)dag, full_dataset_num_items * 128);
    inFile.close();


    uint64_t upper64OfBoundary;
    memcpy(&upper64OfBoundary, boundary.bytes, 8);
    upper64OfBoundary = __bswap_constant_64(upper64OfBoundary);
    std::cout << "upper64OfBoundary ： " <<  upper64OfBoundary << endl;
    pcie_set_target(upper64OfBoundary);

    pcie_set_constants((hash1024*)dag,full_dataset_num_items, nullptr,0); 

    search_results sr;
    pcie_compute_hash(sNonce, header, sr);
            

     if(sr.isfound){
        std::cout << "nonce = " << sr.nonce << " result_hash = " << hash256_to_string(sr.result_hash)<< " header_hash = " << hash256_to_string(sr.header_hash) << endl;
    } else {
        std::cout << " not found!" << std::endl;
    }  

    return 0;
}